#include "../inc/defs.h"

//--------------------------------------------------------------------------------
int
main(void)
{
	tablero juegoAct, juego1Act;
	char ** matAnt, **mat1Ant;
	int opcion, puntajeJ1, puntajeJ2, puntajeJ1ant, puntajeJ2ant, jug1;
	tipotiempo tiempo;
	int comando, comandvalido, flag, flagundo, carga;
	char filename[MAXLONG];
	coordenada pto, pto1;
	int tiempoRest;
	actual juego;
	
	srand(time(NULL));

	/*inicializo variables*/	
	tiempoRest = 1;
	flagundo = 0;
	puntajeJ1 = 0, puntajeJ2 = 0;
	jug1 = 0;
	time_t tIJuego;				/*tiempo inicial de juego*/
	
	opcion = menu();
	switch(opcion){
		case 4:		/*cargar juego*/
			do{
			pedirnombre(filename);
			carga = loadFile(&juego, filename);
			if(carga != 1)
				error(6);			/*nombre inexistente*/
			}while(carga != 1);	
			break;
		case 5:
			return 0;
			break;
		default:								/*arranca un juego nuevo*/
			juegoNuevo(&juegoAct, &juego1Act, &tiempo, opcion);
			break;
	}
	
	/*Reservo espacio en memoria para las dos matrices anteriores*/
	matAnt = armartablero(juegoAct.opciones.dim.x, juegoAct.opciones.dim.x);
	if(opcion == 3)
		mat1Ant = armartablero(juego1Act.opciones.dim.x, juego1Act.opciones.dim.x);
	
	/*Inicializo las dos matrices anteriores y los puntajes*/
	copiarMat(juegoAct.opciones.dim, matAnt, juegoAct.mat);	
	puntajeJ1ant = puntajeJ1;		
	if(opcion == 3)
	{
		copiarMat(juego1Act.opciones.dim, mat1Ant, juego1Act.mat);	
		puntajeJ1ant = puntajeJ1;
	}	
	
	imprimir_matriz(juegoAct.opciones.dim.x, juegoAct.opciones.dim.y, juegoAct.mat,juego1Act.mat, opcion);
	if(opcion == 2)
	{
		tIJuego = time(NULL);	/*tiempo de inicio de juego*/
	}
	do{
		comando = validarcomando(juegoAct, filename, &pto, &pto1, jug1);
		if(comando != SALIR && comando != ERROR)
		{
			if( jug1 == 0 )				/*es el jugador 1*/
			{ 
				if(opcion == 2 && (tiempoRest = tiempo.tiempoT - difftime(time(NULL),tIJuego)) >= 0 )	
					printf("Tiempo restante 00:%2d:%2d\n", tiempoRest/60, tiempoRest%60); 
				if(tiempoRest > 0)					/*si todavia hay tiempo en el caso de juego por tiempo*/
				{
					comandvalido = ejecutarComando(comando, pto, pto1, filename, &juegoAct, matAnt, &puntajeJ1, &puntajeJ1ant, &flagundo, opcion, jug1, tiempoRest, puntajeJ2, juego1Act.mat);
				//	if(comandvalido == 1 )					/*si el comando es valido*/
				//	{	
						imprimir_matriz(juegoAct.opciones.dim.x, juegoAct.opciones.dim.y, juegoAct.mat, juego1Act.mat, opcion);
						printf("Su puntaje es: %d\n", puntajeJ1);
						if(opcion == 3)
							jug1 = 1 - jug1;
				//	}
				}
				else
					comando = SALIR;
			}
			else 				/*es el jugador 2*/
			{
				comandvalido = ejecutarComando(comando, pto, pto1, filename, &juego1Act, mat1Ant, &puntajeJ2, &puntajeJ2ant, &flagundo, opcion, jug1, tiempoRest, puntajeJ1, juegoAct.mat);
			//	if(comandvalido == 1)
			//	{
					imprimir_matriz(juegoAct.opciones.dim.x, juegoAct.opciones.dim.y, juegoAct.mat,juego1Act.mat, opcion);
					printf("Su puntaje es: %d\n", puntajeJ2);
					jug1 = 1 - jug1;
			//	}
			}
		}
	}while(comandvalido != -1 && comando != SALIR );
	if(opcion == 3)
	{
		liberarMat(mat1Ant, juego1Act.opciones.dim);			/*libero las matrices del jugador 2*/
		liberarMat(juego1Act.mat, juego1Act.opciones.dim);
	}
	liberarMat(matAnt, juegoAct.opciones.dim);					/*libero las matrices del jugador 1*/
	liberarMat(juegoAct.mat, juegoAct.opciones.dim);
	
}
//---------------------------------------------------------------------------------
opcJN
pedir_opJN(void)
{
	opcJN  opciones;
	int maxfic, maxlinea;
	
	printf("Ingrese los parametros correspondientes para su nuevo juego,"); 
	printf("en caso de error se le volveran a pedir:\n");
	opciones.dim.x = pedirfil();
	opciones.dim.y = pedircol();
	opciones.cantcolores = pedircolores();	
	maxfic = (opciones.dim.x * opciones.dim.y)/2;
	opciones.cantfichas = pedircantfichas(maxfic);
	maxlinea = ((opciones.dim.x < opciones.dim.y) ? opciones.dim.x : opciones.dim.y);
	opciones.alinea = pediralinea(maxlinea);
	opciones.cantagrega = pedircantagrega();
	return opciones;
}
//---------------------------------------------------------------------------------
int
pedirfil(void)
{
	int fil;
	
	do{
	fil = getint("Ingrese la cantidad de filas, minimo 5:\n");
	}while(fil < DIMMIN || fil > DIMMAX);
	return fil;
}
//---------------------------------------------------------------------------------
int
pedircol(void)
{
	int col;
	
	do{
		col = getint("Ingrese la cantidad de columnas, minimo 5:\n");
	}while(col < DIMMIN || col > DIMMAX );
	return col;
}
//---------------------------------------------------------------------------------
int
pedircolores(void)
{
	int cantcolores;
	
	do{
	cantcolores = getint("Ingrese la cantidad de colores, minimo 2 y maximo 9:\n");
	}while(cantcolores < MINCOL || cantcolores > MAXCOL);
	return cantcolores;
}
//---------------------------------------------------------------------------------
int
pedircantfichas(int maxfic)
{
	int cantfichas;
	
	do{
		cantfichas = getint("Ingrese la cantidad de fichas que hay inicialmente en el tablero:\n");
	}while(cantfichas > maxfic || cantfichas < MINFIC);
	return cantfichas;
}
//-----------------------------------------------------------------------------------
int
pediralinea(int maxlinea)
{
	int alinea;
	
	do{
		alinea = getint("Ingrese la cantidado de bolillas que forman una linea:\n");
	}while(alinea < MINALINEA || alinea > maxlinea);
	return alinea;
}
//------------------------------------------------------------------------------------
int
pedircantagrega(void)
{
	int cantagrega;
	
	do{
		cantagrega = getint("Ingresa la cant de bolillas que se agregan en cada turno:\n");
	}while(cantagrega < MINBOL || cantagrega > MAXBOL);
	return cantagrega;
}
//-----------------------------------------------------------------------------------------
void
pedirnombre(char filename[MAXLONG])
{
	int i;
	int actual;
	
	printf("Ingrese el nombre del archivo que desea cargar, tiene un maximo de 20 caracteres:\n");
	for(i = 0; (i < MAXLONG); i++)
	{
		actual = getchar();
		if(actual == '\n')
			break;
		filename[i] = actual;
	}
		
}

//-----------------------------------------------------------------------------------------
//MODULO DE ERROR
void
error(int num)
{
	switch(num){
		case 0: 
			printf("Coordenada invalida\n");
			break;
		case 1:
			printf("Movimiento invalido\n");
			break;
		case 2:
			printf("Palabra invalida\n");
			break;
		case 3:
			printf("Entrada invalida\n");
			break;
		case 4:
			printf("No hay suficiente espacio en memoria\n");
			break;
		case 5:
			printf("Nombre vacio\n");
			break;
		case 6:
			printf("Nombre inexistente\n");
			break;
		case 7:
			printf("No se pudo guardar el archivo\n");
			break;
		}
		printf("presione enter para continuar\n");
		getchar();
}
//------------------------------------------------------------------------------------------
void
findejuego(int puntaje)
{
	printf("El juego ha terminado.\n");
	printf("Puntaje obtenido:%d\n",puntaje);
	
}
//------------------------------------------------------------------------------------------
int
menu(void)
{
	int i;
	int opcion;
	printf("Elija una de las siguientes modalidades de juego:\n");
	printf("Opcion 1: juego normal\n");
	printf("Opcion 2: juego por tiempo\n");
	printf("Opcion 3: jugadores\n");
	printf("Opcion 4: Cargar juego grabado\n");
	printf("Opcion 5: Terminar\n");
	do{	
		 i=getint("");
	}while(i<=0 || i>=6);

return i;
}
//--------------------------------------------------------------------------------------------
int
validarcomando(tablero tab, char * filename, coordenada * pto, coordenada * pto1, int jugador)
{
	char comando[MAXLONG];
	char s[] = {"ave "};
	char u[] = {"ndo"};
	char q[] = {"uit"};
	int i, j, valid;
	int x, y, x1, y1;
	int dim;
	pedircomando(comando, jugador);
	switch(comando[0]){
		case '[':
				valid = sscanf(comando+1, "%d,%d] [%d,%d]\n",&x, &y, &x1, &y1);			/*me fijo si es una coordenada*/
				if(valid == 4 && x >= 0 && x < tab.opciones.dim.x && y >= 0 && y < tab.opciones.dim.y && 
				x1 >= 0 && x1 < tab.opciones.dim.x && y1 >= 0 && y1 < tab.opciones.dim.y)
				{
					pto->x = x;
					pto->y = y;
					pto1->x = x1;
					pto1->y = y1;
					return MOV;
				}
				else
				{
					error(0);					/*Coordenada invalida*/
					return ERROR;
				}
			break;
		case 'u':
				if(strncmp(comando+1,u,3) == 0 && comando[4] == '\0')		/*me fijo si es un undo*/
					return UNDO;
				else
				{
					error(2);
					return ERROR;
				}
				break;
		case 's':
				if(strncmp(&comando[1],s,4) == 0 && comando[5] != '\0')			/*me fijo si es un save*/
				{
					for(i = 5, j = 0; comando[i] != '\0' && j < MAXLONG; i++, j++)
						filename[j] = comando[i];
					filename[j] = '\0';
					dim = (strlen(filename) < MAXLONG)? strlen(filename) : MAXLONG;
					if(esvacio(filename, dim) == 1)
						return SAVE;
					else
					{
						error(5);
						return ERROR;
					}
				}
				else
				{
					error(2);
					return ERROR;
				}
			break;
		case 'q':															/*me fijo si es un quit*/
				if(strncmp(&comando[1],q,3) == 0 && comando[4] == '\0')
					return SALIR;
				else
				{
					error(2);
					return ERROR;
				}
			break;
		default:
				{	
					error(3);		/*entrada invalida*/
					return ERROR;
				}
			break;
	}
}
//----------------------------------------------------------------------------------
void
pedircomando(char * comando, int jugador)
{
	int i = 0;
	char c;
	
	printf("Jugador %d: ingrese el comando que desea ejecutar, y despues enter:\n", (jugador + 1));
	for(i = 0;(c = getchar()) != '\n'; i++ )
		comando[i] = c;
	comando[i] = '\0';
}
//------------------------------------------------------------------------------------
tipotiempo
pedirtiempo(void)
{
        tipotiempo tiempo;

        do{
                printf("Establezca el tiempo que desea jugar ingresando primero los minutos y luego los segundos:\n");
                tiempo.min=getint("Ingrese la cantidad de minutos:\n");
                tiempo.seg=getint("Ingrese la cantidad de segundos:\n");

       }while( tiempo.min < MINTIME || tiempo.min > MAXTIME || tiempo.seg < MINSEG || tiempo.seg > MAXTIME);

        return tiempo;
}
//-------------------------------------------------------------------------------------
int
juegoNuevo(tablero * tab1, tablero * tab2, tipotiempo * tiempo, int modalidad)
{
	int i, fil, col;
	coordenada pto, * pto1;
	int flag = 1;
		
	tab1->opciones = pedir_opJN();
	pto1 = malloc(tab1->opciones.cantfichas * sizeof(coordenada));	
	if (modalidad == 2)
	{
		*tiempo = pedirtiempo();
		tiempo->tiempoT = tiempo->seg + 60 * tiempo->min; 
	}
	if(modalidad == 3)									//generar los tableros
	{
		tab2->opciones = tab1->opciones; 				//le copio las opciones del tablero a tab2
		tab1->mat = armartablero(tab1->opciones.dim.x, tab1->opciones.dim.y);
		tab2->mat = armartablero(tab2->opciones.dim.x, tab2->opciones.dim.y);	
		if(tab1->mat == NULL || tab2->mat == NULL)
			flag = 0;
	}
	else 
	{	
		tab1->mat = armartablero(tab1->opciones.dim.x , tab1->opciones.dim.y );
		if(tab1->mat == NULL)
			flag = 0;
	}
	for(i = 0; i < tab1->opciones.cantfichas ; i++)			//asignarle los colores en posiciones aleatorias
	{
		do{
		pto.x = randint(0 , (tab1->opciones.dim.x - 1));
		pto.y = randint(0, (tab1->opciones.dim.y - 1));
		}while(comparaptos(pto, pto1, i) == 0);
		pto1[i] = pto;
		if(modalidad == 3)
		{
			asignarColor(tab1->mat, pto, tab1->opciones.cantcolores);
			asignarColor(tab2->mat, pto, tab2->opciones.cantcolores);
		}
		else
			asignarColor(tab1->mat, pto, tab1->opciones.cantcolores);
	}
	free(pto1);
	return flag;
}
//-------------------------------------------------------------------------------------
void
imprimir_matriz(int fil,int col,char ** mat1,char ** mat2,int modalidad)
{

        int i,j;
        printf("    ");
        for(j=0;j<col;j++)
                printf("%3d",j);
        if(modalidad==DOS_JUGADORES)
                {
                        printf(" \t   |  \t ");
                        printf("    ");
                        for(j=0;j<col;j++)
                        printf("%3d",j);
                }

        printf("\n");
        printf("    ");
        for(j=0;j<col;j++)
               {
                printf("---");
                }

        if(modalidad==DOS_JUGADORES)
        {
		 printf("\t   | \t ");
               		printf("    ");
                for(j=0;j<col;j++)
               		 printf("---");
        }
      	printf("\n");
        for(i=0;i<fil;i++)
        {
                printf("%3d|",i);
                for(j=0;j<col;j++)
                            printf("%3d",mat1[i][j]);
                if(modalidad==DOS_JUGADORES)
                        {
                                printf(" \t   | \t ");
                                printf("%3d|",i);
                                for(j=0;j<col;j++)
                                        printf("%3d",mat2[i][j]);
                        }

                printf("\n");
       }

}

//---------------------------------------------------------------------------------------------------
//devuelve 0 si el movimiento es valido, 1 sino. 
//llama a si el camino es posible, y si es posible lo ejecuta
int
ejecutarMov(tablero * tab, coordenada pto, coordenada pto1)
{
	int flag = 1; /*lo setea en 0 cuando el movimiento es valido*/	
	int e = 0;
	
	if(((pto.x != pto1.x) || (pto.y != pto1.y)) && (tab->mat[pto.x][pto.y] != 0 ) && (tab->mat[pto1.x][pto1.y] == 0)) 
		/*las dos coordenadas de los puntos tienen que ser distintas, el pto1 tiene que tener un color y pto1 tiene que ser un blanco*/
	{
		if(existeCam( tab, pto.x, pto.y, pto1.x, pto1.y, &e) == 1)
		{
			tab->mat[pto1.x][pto1.y] = tab->mat[pto.x][pto.y];
			tab->mat[pto.x][pto.y] = 0;
			flag = 0;
		}
		else
			error(1);		/*movimiento invalido*/
	}
	else
		error(1);			/*coordenada invalida*/
	return flag;
}

//------------------------------------------------------------------------------------
//devuelve 1 si el comando ingresado se puede ejecutar, 0 sino y -1 si el juego termino
int
ejecutarComando(int comando, coordenada pto, coordenada pto1, char filename[MAXLONG], tablero * juegoAct, char ** juegoAnt, int * puntaje, int *puntajeAnt, int *flagundo , int modalidad, int jug1, int tiempoRest, int puntaje1, char **mat )
{
	int dimvec;
	int flagMov;				/*se setea en 1 si el movimiento es valido, 0 sino*/
	coordenada * vecBlancos;
	int esvalido = 0;			/*se setea en 1 si el comando ingresado es valido y en -1 si termino el juego*/
	tablero juegoAux;
	coordenada ptonuevo, * vecptosnuevo;
	int i;
	actual juego;
	
	switch(comando)
	{
		case MOV:
			juegoAux.mat = juegoAct->mat;
			juegoAux.opciones.dim = juegoAct->opciones.dim;
			juegoAux.opciones.cantcolores = juegoAct->opciones.cantcolores;
			juegoAux.opciones.cantfichas = juegoAct->opciones.cantfichas;
			juegoAux.opciones.alinea = juegoAct->opciones.alinea;
			juegoAux.opciones.cantagrega = juegoAct->opciones.cantagrega;
			
			copiarMat(juegoAct->opciones.dim, juegoAnt, juegoAct->mat); 			/*cambio el juegoAnt por el juegoActual*/
			
			flagMov = ejecutarMov(&juegoAux, pto, pto1);
			if(flagMov != 1)							/*ejecuto el movimeinto*/
			{	
				if(alinea( juegoAux, puntaje, 1 ) != 1) 			/*le paso 1 para indicar que viene de un movimiento*/
			  	{
					if( ((vecBlancos = buscaNespa( juegoAux, &dimvec)) != NULL) && (
						(vecptosnuevo = malloc( juegoAux.opciones.cantagrega * sizeof(coordenada) )) != NULL) ) /*se fija q halla lugar para agregar bolitas y
					 																				que pueda chequear que no repita posiciones*/
		 	  		{
					
			    		for ( i = 0 ; i < juegoAux.opciones.cantagrega ; )
				    	{
							do{
								ptonuevo = asignarPos(vecBlancos, dimvec);	
							}while( comparaptos ( ptonuevo, vecptosnuevo , i ) != 1);
							vecptosnuevo[i] = ptonuevo;
					  		asignarColor ( juegoAux.mat, ptonuevo, juegoAux.opciones.cantcolores );
					  		alinea (juegoAux, puntaje, 0);
							i++;
						}
						free(vecBlancos);
				    	free(vecptosnuevo); 
						*flagundo = 0;
						
				 	}
				 	else
			  		{
			    		findejuego (*puntaje);
						esvalido = -1;
			  		}
				}
				copiarMat(juegoAct->opciones.dim, juegoAct->mat, juegoAux.mat); 		/*cambio el juegoAct por el modificado */
																						/*despues de ejecutar el comando*/
				esvalido = 1;
			}
			break;
		case UNDO:
			if(*flagundo == 0 && modalidad != 3)			/*si no se hizo un undo en la jugada anterior*/
			{

				copiarMat(juegoAct->opciones.dim, juegoAct->mat, juegoAnt);
				*flagundo = 1;
			}
			else
				error(1);			/*Movimiento invalido*/
			break;
		case SAVE:
			/*guardar archivo*/

			juego.Tjuego = modalidad;
			juego.Trestante = tiempoRest;
			juego.proxturno = (jug1 == 1)?1:2;
			juego.dimfil = juegoAct->opciones.dim.x;
			juego.dimcol = juegoAct->opciones.dim.y;
			juego.cantcolor = juegoAct->opciones.cantcolores;
			juego.cantalinea = juegoAct->opciones.alinea;
			juego.cantagrega = juegoAct->opciones.cantagrega;
			juego.puntaje1 = (jug1 == 0) ? *puntaje : puntaje1;
			juego.puntaje2 = (jug1 == 1) ? *puntaje : puntaje1;
			juego.sec1 = (jug1 == 0) ? juegoAct->mat : mat;
			juego.sec2 = (jug1 == 1) ? juegoAct->mat : mat;
			esvalido = saveFile(&juego, filename);
			if(esvalido != 1)
				error (7);
			break;
		}
		return esvalido;
}
